<template>
  <div ref="fatherBox" class="myTinymcejsX" :class="{'hiddenStatus':hiddenStatus}">
    <span class="showBox" v-if="showTinymce">
      <textarea class="textareaDom" v-model="textContentObj.text"></textarea>
    </span>
  </div>
</template>

<script>
import {nextTick, watch,ref} from 'vue'

// 判断prop传参的值。接受[String,Number]的style样式尺寸
function getPx(text, defaultPx = 'px') {
  let tempList = ['px', 'rpx', 'vw', 'vh', '%', 'em', 'auto']
  if (typeof text == 'string') {
    const havePx = tempList.find(row => text.includes(row))
    if (havePx) {
      return text
    } else {
      return `${parseFloat(text)}${defaultPx}`
    }
  } else if (typeof text == 'number') {
    let temp = parseFloat(text)
    return `${temp}${defaultPx}`
  }
  return text
}

export default {
  name: "myTinymcejsX",

  props: {
    // 内容
    modelValue: {
      type: [String, Object],
      default: ''
    },

    // 文件根路径(暂时手动复制到public文件夹)
    baseUrl: {
      type: String,
      default: "/"
    },

    // 高度
    height: {
      type: [String, Number, undefined],
      default: '100%'
    },

    // 语言
    language: {
      type: String,
      default: "zh-Hans"
    },

    // 不显示菜单栏。
    noMenu: {
      type: Boolean,
      default: false
    },

    // 自定义菜单栏
    myMenu: {
      type: Object,
      // default: {
      //   my2: {title: '我的菜单2234', items: 'copy paste formats'},
      //   my1: {title: '我的菜单1', items: 'copy paste formats'},
      // },
      default: undefined
    },

    // 占位内容
    placeholder: {
      type: String,
      default: "在这里输入文字"
    },


    plugins: {
      type: [String, Object],
      default: [
        'advlist', 'code', 'codesample', 'autolink', 'anchor',
        'directionality', 'nonbreaking',
        'lists', 'link', 'image', 'preview', 'searchreplace', 'visualblocks', 'visualchars',
        'pagebreak', 'anchor', 'fullscreen', 'insertdatetime',
        'media', 'table', 'help', 'wordcount', 'autosave', 'emoticons',
      ]
    },

    // 工具栏配置
    toolbar: {
      type: Object,
      default: [
        // 列表时。第一个是isLine含义。后面的则查找prop或者style
        [false, "undo", 'redo'],
        [false, "fullscreen", 'code'],
        [false, 'fontDecoration'],
        [false, "align",],
        [false, 'styleSelect'],
        [true, 'links'],
        [false, 'color'],
        {prop: "table", isLine: false},
        {style: "font", blackList: ['pagebreak', 'insertdatetime', 'visualblocks']},
        {style: "fontStyle", blackList: ['lineheight', 'insertdatetime', 'visualblocks']},
      ],
      // default: undefined
    },

    // 隐藏工具类。
    noTool: {
      type: Boolean,
      default: false
    },

    // 自定义工具类
    myTool: {
      type: Object,
      default: [
        // {
        //   prop: 'wxUrl',
        //   icon: 'wxUrl',
        //   tooltip: '文章链接',
        //   style: 'myButton',
        //   htmlStr: '<div style="font-size: 12px;text-align: center;">文章链接</div>',
        //   click: () => {
        //     console.log('打开弹窗')
        //   }
        // },
      ]
    },

    // content_css: 'plugins/becodesample/highlight.js-11.5.1/styles/atom-one-light.css',

    // 插件前回调函数。第一个参数是富文本对象，第二个是init配置对象
    beforeFn: {
      type: Function,
      default: undefined
    },


    // 自定义菜单-格式的格式列表
    styleFormats: {
      type: Object,
      // default: [
      //   {
      //     // 自定义名称
      //     title: '行高',
      //     items: [
      //       {title: '0.5', block: 'p', styles: {'line-height': '0.5'}},
      //       {title: '0.8', block: 'p', styles: {'line-height': '0.8'}},
      //       {title: '1.0', block: 'p', styles: {'line-height': '1.0'}},
      //       {title: '1.2', block: 'p', styles: {'line-height': '1.2'}},
      //       {title: '1.4', block: 'p', styles: {'line-height': '1.4'}},
      //       {title: '1.6', block: 'p', styles: {'line-height': '1.6'}},
      //       {title: '1.8', block: 'p', styles: {'line-height': '1.8'}},
      //       {title: '2.0', block: 'p', styles: {'line-height': '2.0'}},
      //       {title: '2.2', block: 'p', styles: {'line-height': '2.2'}},
      //       {title: '2.4', block: 'p', styles: {'line-height': '2.4'}},
      //     ]
      //   }
      // ],
      default: undefined
    },

    // 自定义菜单-格式的格式列表的添加方式：false替换还是true添加
    styleFormatAdd: {
      type: Boolean,
      default: true
    },

    // 是否只读
    onlyRead: {
      type: Boolean,
      default: false
    },

    // 颜色框默认列表
    fontColor: {
      type: Object,
      default: undefined
    },

    // setup回调
    setupFn: {
      type: Function,
      default: undefined
    },

    // 工具栏回调函数
    toolbarFn: {
      type: Function,
      default: undefined
    },

    // 是否调整高度
    resize: {
      type: Boolean,
      default: true
    },

    // 初始化结束
    isOk: {
      type: Function,
      default: undefined
    },

    // 最小高度
    minHeight: {
      type: [String, Number],
      default: undefined
    },

    // 不需要滚动条
    noScroll: {
      type: Boolean,
      default: false
    },

    // 隐藏底部字符状态栏
    hiddenStatus: {
      type: Boolean,
      default: false
    },

    // 圆角大小
    radius: {
      type: [String, Number],
      default: 10
    },

  },

  data() {
    return {
      // 内容对象。使用对象是为了ContentTool类的参数对象保持内存地址指向不变
      textContentObj: {
        text: ''
      },

      // 富文本的dom的id
      domId: "",

      // 显示组件
      showTinymce: true,

      // 初始化配置
      initD: {},

      // 工具类
      toolSetting: [
        // 文件
        {label: '新文档(清空内容)', prop: 'newdocument', plugins: '', style: 'document'},
        {label: '全选', prop: 'selectall', plugins: '', style: 'document'},
        {label: '剪切', prop: 'cut', plugins: '', style: 'document'},
        {label: '复制', prop: 'copy', plugins: '', style: 'document'},
        {label: '粘贴', prop: 'paste', plugins: '', style: 'document'},
        {label: '撤销', prop: 'undo', plugins: '', style: 'document'},
        {label: '重做/重复', prop: 'redo', plugins: '', style: 'document'},
        {label: '查找/替换', prop: 'searchreplace', plugins: 'searchreplace', style: 'document'},

        // 文本修饰
        {label: '加粗', prop: 'bold', plugins: '', style: 'fontDecoration'},
        {label: '斜体', prop: 'italic', plugins: '', style: 'fontDecoration'},
        {label: '下划线', prop: 'underline', plugins: '', style: 'fontDecoration'},
        {label: '删除线', prop: 'strikethrough', plugins: '', style: 'fontDecoration'},
        {label: '引用', prop: 'blockquote', plugins: '', style: 'fontDecoration'},
        {label: '下角标', prop: 'subscript', plugins: '', style: 'fontDecoration'},
        {label: '上角标', prop: 'superscript', plugins: '', style: 'fontDecoration'},

        // 字体设置
        {label: '行高 5.5版本新增', prop: 'lineheight', plugins: '', style: 'fontStyle'},
        {label: '文本大小', prop: 'fontsize', plugins: '', style: 'fontStyle'},
        {label: '字体族', prop: 'fontfamily', plugins: '', style: 'fontStyle'},
        {label: '字体族', prop: 'styles', plugins: '', style: 'fontStyle'},


        // 对齐方式
        {label: '左对齐', prop: 'alignleft', plugins: '', style: 'align'},
        {label: '居中对齐', prop: 'aligncenter', plugins: '', style: 'align'},
        {label: '右对齐', prop: 'alignright', plugins: '', style: 'align'},
        {label: '两端对齐', prop: 'alignjustify', plugins: '', style: 'align'},
        {label: '减少缩进', prop: 'outdent', plugins: '', style: 'align'},
        {label: '增加缩进', prop: 'indent', plugins: '', style: 'align'},


        // 选择器
        // {label: '自定义段落样式格式', prop: 'styleselect', plugins: '', style: 'styleSelect'},
        // {label: '段落格式', prop: 'fontsizeselect', plugins: '', style: 'styleSelect'},
        // {label: '字体选择', prop: 'fontselect', plugins: '', style: 'styleSelect'},
        // {label: '字号选择', prop: 'fontsizeselect', plugins: '', style: 'styleSelect'},
        // {label: '字号选择', prop: 'formats', plugins: '', style: 'styleSelect'},
        {label: '项目列表UL', prop: 'bullist', plugins: 'lists', style: 'styleSelect'},
        {label: '编号列表OL', prop: 'numlist', plugins: 'lists', style: 'styleSelect'},

        // 颜色
        {label: '文本颜色', prop: 'forecolor', plugins: '', style: 'color'},
        {label: '背景颜色', prop: 'backcolor', plugins: '', style: 'color'},

        // 链接
        {label: '网页链接', prop: 'link', plugins: 'link', style: 'links'},
        {label: '网页锚点', prop: 'anchor', plugins: 'anchor', style: 'links'},
        {label: '图片', prop: 'image', plugins: 'image', style: 'links'},
        {label: '媒体', prop: 'media', plugins: 'media', style: 'links'},
        // {label: '无效', prop: 'axupimgs', plugins: '', style: 'links'},

        // 字符和表情
        {label: '特殊字符', prop: 'charmap', plugins: 'charmap', style: 'font'},
        {label: '图标', prop: 'emoticons', plugins: 'emoticons', style: 'font'},
        {label: '水平分割线', prop: 'hr', plugins: '', style: 'font'},
        {label: '分页符', prop: 'pagebreak', plugins: 'pagebreak', style: 'font'},
        {label: '日期时间', prop: 'insertdatetime', plugins: 'insertdatetime', style: 'font'},
        {label: '显示区域块边框', prop: 'visualblocks', plugins: 'visualblocks', style: 'font'},

        // 打印
        {label: '打印', prop: 'print', plugins: '', style: 'print'},
        {label: '预览', prop: 'preview', plugins: 'preview', style: 'print'},


        // 其他
        {label: '全屏', prop: 'fullscreen', plugins: 'fullscreen', style: 'other'},
        {label: '编辑源代码', prop: 'code', plugins: 'code', style: 'other'},
        {label: '清除格式', prop: 'removeformat', plugins: '', style: 'other'},
        {label: '恢复上次的草稿', prop: 'restoredraft', plugins: 'autosave', style: 'other'},
        {label: '粘贴为文本', prop: 'pastetext', plugins: '', style: 'other'},
        {label: '表格', prop: 'table', plugins: 'table', style: 'other'},
        // {label: '', prop: 'indent2em', plugins: '', style: 'other'},
        // {label: '', prop: 'formatpainter', plugins: '', style: 'other'},

      ],

      // 当前插件集合
      pluginsList: [],

      // 当前tinymce对象
      tinymceObj: undefined,

      // 工具类
      myUi: {},

      // 工具类添加的按钮列表
      buttonToolList: [],

      // 内容工具
      contentTool: {},

    }
  },

  methods: {
    // 初始化
    init(options = undefined) {
      let that = this;
      this.showTinymce = false
      if (window.tinymce) {
        setTimeout(() => {
          this.showTinymce = true
          nextTick(async () => {
            this.changeId()
            // 配置设置项
            if (options) {
              this.initD = options
            } else {
              const tempDefault = await this.getDefault()
              // console.log(324,tempDefault)
              if (this.beforeFn && typeof this.beforeFn == 'function') {
                await this.beforeFn(tempDefault)
              }
              this.initD = tempDefault
            }

            // 重新初始化
            Object.assign(this.initD, {
              selector: `textarea#${this.domId}`,
              // 保存对象
              setup(editor) {
                that.tinymceObj = editor
                that.myUi = new UiTool(editor, that)
                // 双向绑定内容
                editor.on('change redo undo input insert', () => {
                  const text = editor.getContent()
                  if (text != that.textContentObj.text) {
                    that.textContentObj.text = text
                    that.$emit('update:modelValue', that.textContentObj.text)
                  }
                })

                // 添加自定义按钮
                for (let i = 0; i < that.buttonToolList.length; i++) {
                  const config = that.buttonToolList[i]
                  that.myUi.addButton(config, false)
                }

                // 自定义工具栏
                if (that.myTool?.length > 0 && that.myTool instanceof Array) {
                  for (let i = 0; i < that.myTool.length; i++) {
                    const config = that.myTool[i]
                    that.myUi.addButton(config, false)
                  }
                }

                // 调用前函数
                if (that.setupFn != undefined && typeof that.setupFn == 'function') {
                  that.setupFn(editor, that.initD, that)
                }
              },
            })

            tinymce.init(this.initD)
            this.contentTool = new ContentTool(this.textContentObj, this.tinymceObj)
            if (this.isOk && typeof this.isOk == 'function') {
              this.isOk(this)
            }

          })
        }, 10)
      }
    },

    // 处理工具栏
    getTool() {
      // 隐藏工具栏
      if (this.noTool == true) {
        return false
      }
      // 当前要显示的工具栏
      let tempBarList = []
      if (this.toolbar != undefined && this.toolbar.length > 0) {
        tempBarList.push(...JSON.parse(JSON.stringify(this.toolbar)))
      }

      let result = []
      let toolList = []

      // 工具栏类别列表
      let tempToolList = JSON.parse(JSON.stringify(this.toolSetting))

      if (this.buttonToolList?.length > 0) {
        tempToolList.push(...this.buttonToolList)
      }
      if (this.myTool.length > 0) {
        tempToolList.push(...this.myTool)
      }
      tempToolList = JSON.parse(JSON.stringify(tempToolList))

      // 处理对象类型
      function _isObj(item) {
        // 获取到符合这个分类的
        const tempStyle = item.style?.toLowerCase() || ""
        // 获取符合这个prop的
        const tempProp = item.prop?.toLowerCase() || ""
        // 黑名单
        const blackList = item.blackList || []
        // 是否换行
        const isLine = item.isLine

        // 找到符合的分类
        let okTool = []

        tempToolList.forEach(row => {
          if (row.style?.toLowerCase() == tempStyle || (tempProp && row.prop?.toLowerCase() == tempProp)) {
            // 相同分类或prop，而且不在黑名单里
            const isBlack = blackList.find(blackItem => blackItem.toLowerCase() == row.prop.toLowerCase())
            if (!isBlack) {
              okTool.push(row.prop)
              toolList.push(row)
              return true
            }
          }
        })

        // 添加到工具栏
        if (result.length <= 0) {
          result.push(okTool.join(" "))
        } else {
          // 判断是否换行处理
          if (isLine) {
            result.push(okTool.join(" "))
          } else {
            result[result.length - 1] = result[result.length - 1] + `|${okTool.join(' ')}`
          }
        }


      }

      // 处理列表类型
      function _isArray(list) {
        // 将prop和style等于这个name的都找出来
        let okTool = []
        let isLine = list.shift()
        list.forEach(name => {
          let tempName = name.toLowerCase()
          tempToolList.forEach(row => {
            // 查找分类
            if (row.prop?.toLowerCase() == tempName || row.style?.toLowerCase() == tempName) {
              okTool.push(row.prop)
              toolList.push(row)
            }
          })


        })
        // 添加到工具栏
        if (result.length <= 0) {
          result.push(okTool.join(" "))
        } else {
          // 判断是否换行处理
          if (isLine) {
            result.push(okTool.join(" "))
          } else {
            result[result.length - 1] = result[result.length - 1] + `|${okTool.join(' ')}`
          }
        }
      }

      tempBarList.forEach(item => {
        if (item instanceof Array && item.length >= 2) {
          _isArray(item)
        } else if (item) {
          _isObj(item)
        }
      })

      // 添加插件
      toolList.forEach(row => {
        if (row.plugins && !this.pluginsList.includes(row.plugins)) {
          this.pluginsList.push(row.plugins)
        }
      })

      return result

    },

    // 处理菜单栏
    showMenu() {
      // 不显示菜单
      if (this.noMenu == true) {
        return false
      }
      // 判断是否为自定义菜单
      if (this.myMenu) {
        let tempBar = []
        for (let key in this.myMenu) {
          tempBar.push(key)
        }
        return tempBar.join(' ')
      }

      return true
    },

    // 处理字体颜色
    makeFontColor() {
      let result = []
      const tempObj = this.fontColor != undefined ? this.fontColor : {
        '#FFC0CB': '粉红',
        '#F56C6C': '浅红',
        '#FF0000': '纯红',
        '#632523': '黑红',
        '#800080': '紫色',

        '#FFFFFF': '白',
        '#FCD5B5': '浅橙',
        '#FAC090': '橙色',
        '#E46C0A': '橘橙',
        '#984807': '深橙',

        '#C6D9F1': '白蓝',
        '#8EB4E3': '浅蓝',
        '#558ED5': '蓝色',
        '#3366FF': '海蓝',
        '#0000FF': '纯蓝',

        '#D7E4BD': '浅绿',
        '#03FA03': '荧光',
        '#67c23a': '浅绿',
        '#1AAD19': '深绿',
        '#77933C': '棕绿',

        '#FFFF03': '黄色',
        '#7F7F7F': '灰色',
        '#0D0D0D': '黑色',
      }
      for (let key in tempObj) {
        result.push(key)
        result.push(tempObj[key])
      }
      if (result.length <= 0) {

      }
      return result
    },

    // 获取默认的配置项
    async getDefault() {
      this.pluginsList = []
      // 获取工具栏列表
      const toolList = await this.getTool()
      // 判断是否存在工具栏回调函数
      if (this.toolbarFn && typeof this.toolbarFn == 'function') {
        await this.toolbarFn(toolList)
      }


      // 获取菜单列表
      const menubar = await this.showMenu()
      // 添加插件
      if (this.plugins) {
        this.plugins.forEach(item => {
          if (!this.pluginsList.includes(item)) {
            this.pluginsList.push(item)
          }
        })
      }
      // 是否不需要滚动条
      if (this.noScroll) {
        this.pluginsList.push('autoresize')
      }

      return {
        // 高度
        height: this.height,
        // 最小高度。如果需要由内容撑开，这需要配合autoresize插件
        min_height: this.minHeight != undefined ? parseFloat(this.minHeight) : undefined,

        //语言类型
        language: this.language,

        //textarea中的提示信息
        placeholder: this.placeholder,
        //图片是否可粘贴
        paste_data_images: false,
        // 右下角的tiny技术支持信息是否显示
        branding: false,
        // 颜色选择框
        color_map: this.makeFontColor(),
        // 颜色选择框多少列
        color_cols: 5,
        // 组件根路径
        // base_url: props.baseUrl,

        fontsize_formats: '12px 14px 16px 18px 24px 36px 48px 56px 72px',
        //字体样式
        font_formats: "微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC," +
            "Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei," +
            "sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black," +
            "avant garde;Book Antiqua=book antiqua,palatino;",

        lineheight_formats: '0.5 0.8 1 1.2 1.4 1.6 1.8 2 2.2 2.4',
        // 弹窗可拖动
        draggable_modal: true,
        // 是否只读
        readonly: this.onlyRead,
        // 调整高度
        resize: this.resize,

        /* 菜单栏 */
        // 显示菜单栏
        menubar: menubar,
        menu: this.myMenu,


        /* 工具栏 */
        // 格式-格式
        style_formats: this.styleFormats,
        style_formats_merge: this.styleFormatAdd,

        // plugins: props.plugins,
        plugins: this.pluginsList,

        // 工具栏配置，设为false则隐藏
        toolbar: toolList,

        //file image media分别对应三个类型文件的上传：link插件，image和axupimgs插件，media插件。想屏蔽某个插件的上传就去掉对应的参数
        file_picker_types: "file image media",
        // toolbar_persist: true,

      }
    },

    // 改变domId
    changeId() {
      const thisDom = this.$refs.fatherBox.querySelector('.textareaDom');
      // 修改id，防止和别的相同
      let tempId = `myTinymcejsX_${Date.now()}`
      // 判断这个id是否已经存在
      while (true) {
        let haveDom = document.getElementById(tempId)
        if (haveDom) {
          // 存在则换一个id
          tempId = `myTinymcejsX_${Date.now()}`
        } else {
          break;
        }
      }
      // 修改id
      if (thisDom != null && thisDom != undefined) {
        thisDom.setAttribute('id', tempId)
        this.domId = tempId
      }
    },

  },

  watch: {
    'modelValue': {
      handler(newValue) {
        if (newValue != this.textContentObj.text) {
          this.textContentObj.text = newValue
          if (this.tinymceObj) {
            this.tinymceObj.setContent(newValue)
          }
        }
      },
      immediate: true,
      deep: true
    },

    onlyRead: {
      handler(newV) {
        if (this.tinymceObj) {
          this.tinymceObj.mode.set(newV ? 'readonly' : 'design');
        }
      },
      immediate: true
    }
  },

  mounted() {
    this.init()
  },

  computed: {
    radiusSize() {
      return getPx(this.radius)
    }
  }

}

// #Api：https://www.tiny.cloud/docs/tinymce/latest/apis/tinymce.editor

// Ui工具类型
class UiTool {
  constructor(ed, that) {
    // 这个组件对象
    this.that = that
    this.ed = ed
  }

  // 修改工具组件渲染
  showUi() {

  }

  // 添加工具组件。
  addButton(config = {}, isShow = undefined) {
    config.prop = config.prop || String(new Date().getTime())
    config.id = config.id ? config.id : config.prop
    config.style = config.style || 'addButton'
    config.icon = config.icon || 'xhyk'
    config.tooltip = config.tooltip || '按钮'
    const tempFn = () => {

    }
    config.onAction = config.click || tempFn

    // 默认是进行显示按钮。后面的添加就不需要了，因为要重新加载了
    if ((config.show == true || config.show == undefined) && isShow != false) {
      config.show = true
      // 添加到按钮列表
      const haveBn = this.that.buttonToolList.find(row => row.prop == config.prop)
      if (!haveBn) {
        this.that.buttonToolList.push(config)
        // 重新加载
        this.that.init()
        return;
      }
    }

    // 判断是否需要添加图标
    if (config.htmlStr) {
      this.addIcon({
        icon: config.icon,
        htmlStr: config.htmlStr
      })
    }

    this.ed?.ui.registry.addButton(config.prop, config)
  }

  addIcon(config = {}) {
    let icon = config.icon || 'xhyk'
    let htmlStr = config.htmlStr || '<svg height="24" width="24"><path d="M12 0 L24 24 L0 24 Z" /></svg>'
    this.ed?.ui.registry.addIcon(icon, htmlStr)
  }
}

// 内容工具
class ContentTool {
  constructor(textObj, tinyObj) {
    this.ed = tinyObj
    this.textObj = textObj
    this.re = new ReStr()
  }

  // 提取图片
  getImg() {
    let result = []
    let tempList = this.re.getImg(this.textObj.text) || []
    tempList.forEach(item => {
      const url = this.re.getStrCenter(item, 'src="', '"', undefined)
      result.push({
        img: item,
        url: url
      })
    })
    return result
  }

  // 提取视频
  getVideo() {
    let result = []
    let tempList = this.re.getVideo(this.textObj.text) || []
    tempList.forEach(item => {
      const url = this.re.getStrCenter(item, 'src="', '"', undefined)
      const poster = this.re.getStrCenter(item, 'poster="', '"', undefined)
      result.push({
        video: item,
        url: url,
        poster: poster
      })
    })
    return result
  }

  // 取内容
  getContent() {
    return this.ed.getContent()
  }

  // 取内容长度
  getLength() {
    return this.textObj.text.length;
  }

  // 获取选中的范围。返回前后位置和选中内容
  getSelectText() {
    let result = {
      text: '',
      start: -1,
      end: -1
    }
    let tempObj = this.ed?.selection.getRng() || {}
    if (tempObj.startOffset != undefined) {
      result.start = tempObj.startOffset
      result.end = tempObj.endOffset
      if (tempObj.commonAncestorContainer.nodeValue) {
        result.text = tempObj.commonAncestorContainer.textContent.slice(result.start, result.end)
      } else {
        result.text = tempObj.commonAncestorContainer.textContent
      }
    }

    return result
  }

  // 在索引处(当前光标位置)，插入内容。在非纯文本内容中，index参数不是很好兼容
  insertContent(text, index = undefined) {
    if (index == undefined) {
      index = 0
      this.ed?.insertContent(text)
    } else {
      this.move(index)
      this.ed?.insertContent(text)
    }
  }


  // 替换全部内容
  setContent(text) {
    this.ed?.setContent(text)
  }

  // 全选
  selectAll() {
    return this.ed?.execCommand('selectAll') || false
  }

  // 获取当前光标位置
  getFocus() {
    return this.getSelectText().start
  }

  // 设置焦点
  setFocus() {
    this.ed?.focus()
  }

  // 光标移到尾部或者头部。
  moveStartOrEnd(start = true) {
    this.selectAll()
    this.ed?.selection.getRng().collapse(start)
    this.setFocus()
  }

  // 将光标移到指定位置。对应非纯文本不好处理
  move(index = 0) {
    const selection = this.ed?.selection || {}
    this.setFocus()
    const length = this.getLength()
    if (index >= length - 1) {
      index = length
    } else if (index <= 0) {
      index = 0
    }
    selection.getRng().setStart(selection.getRng().startContainer, index);
    selection.getRng().setEnd(selection.getRng().endContainer, index);
    // 重新设置选区
    selection.setRng(selection.getRng());
  }

  // 获取当前节点的内容
  getNow() {
    return this.ed.selection.getContent()
  }

  // 判断是否为图片
  isImg(text = undefined) {
    if (text == undefined) {
      text = this.getNow()
    }
    let result = undefined
    let list = this.re.getImg(text)
    if (list?.length > 0) {
      let url = this.re.getStrCenter(list[0], 'src="', '"', '')
      result = {
        url: url,
        dom: list[0]
      }
    }
    return result
  }

  // 判断是否为视频
  isVideo(text = undefined) {
    if (text == undefined) {
      text = this.getNow()
    }
    let result = undefined
    let list = this.re.getVideo(text)
    if (list?.length > 0) {
      let url = this.re.getStrCenter(list[0], 'src="', '"', '')
      result = {
        url: url,
        dom: list[0]
      }
    }
    return result
  }


  // 创建节点。
  // tinymce.activeEditor.selection.setNode(tinymce.activeEditor.dom.create('img', { src: 'some.gif', title: 'some title' }));
  createNode(name, data = {}) {
    return this.ed.dom.create(name, data)
  }

  // 改变节点
  changeNode(newNode) {
    this.ed?.selection.setNode(newNode)
  }

  // 获取当前节点
  getNode() {
    return this.ed.selection.getNode()
  }
}

// 正则类
class ReStr {

  static get reText() {
    return {
      // img: `<[img|image][^>]+>`,
      img: `(<(img|image).*?src=")(.*?)(".*?>)`,
      video: `(<video.*?src=")(.*?)(".*?>)(.*</video>){0,1}`,
    }
  }

  constructor(regExp, flags = 'g') {
    this.regExp = regExp // 正则表达式
    this.flags = flags // 正则表达式标识
    this.reObj = undefined // 正则表达式对象
    if (regExp != undefined) {
      this.create()
    }

  }


  // 创建正则表达式对象
  create(reExp, flags) {
    if (reExp != undefined) {
      this.regExp = reExp
    }
    if (flags != undefined) {
      this.flags = flags
    }
    this.reObj = new RegExp(this.regExp, this.flags)
  }

  // 一次匹配
  exec(text) {
    return this.reObj.exec(text)
  }

  // 匹配多次
  match(text) {
    return text.match(this.reObj)
  }

  // 取文本中间
  getStrCenter(text, reBefore, reAfter, False = '', flags = 'g') {
    try {
      let tempReObj = new RegExp(reBefore, flags)
      const strBefore = tempReObj.exec(text)
      if (!strBefore) {
        return False
      }
      tempReObj = new RegExp(reAfter, flags)
      const strAfter = tempReObj.exec(text)
      if (!strAfter) {
        return False
      }
      let before = text.indexOf(strBefore[0]);
      let after = text.indexOf(strAfter[0], before + strBefore[0].length);
      if (before == -1 || after == -1) {
        return False
      } else {
        return text.slice(before + strBefore[0].length, after)
      }
    } catch (err) {
      return False
    }

  }


  // 提取图片
  getImg(text, flags = undefined) {
    this.create(ReStr.reText.img, flags)
    let result = this.match(text)
    return result
  }

  // 提取视频
  getVideo(text, flags) {
    this.create(ReStr.reText.video, flags)
    let result = this.match(text)
    return result
  }
}

</script>

<style scoped lang="scss">
.myTinymcejsX {
  height: 100%;

  :deep(.tox-tinymce) {
    border-radius: v-bind(radiusSize);
  }
}

.hiddenStatus {
  :deep(.tox-statusbar) {
    display: none !important;
  }
}
</style>

<style lang="scss">
// 隐藏警告
.tox-notifications-container, .tox-promotion {
  display: none !important;
}

.tox-tinymce-aux {
  z-index: 5000 !important;
}

.tinymce.ui.FloatPanel {
  z-index: 5000 !important;
}

</style>